package com.goldpac.jssb.service.base.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.goldpac.jssb.common.BaseRequest;
import com.goldpac.jssb.common.BaseResponse;
import com.goldpac.jssb.common.CommonHttpClient;
import com.goldpac.jssb.common.EBodyFormat;
import com.goldpac.jssb.common.HttpClientConfiguration;
import com.goldpac.jssb.common.HttpMethodName;
import com.goldpac.jssb.common.ZXingCode;
import com.goldpac.jssb.model.base.Param;
import com.goldpac.jssb.model.command.SyncInfoCommand;
import com.goldpac.jssb.pojo.vo.sical.BaseRp;
import com.goldpac.jssb.pojo.vo.sical.PayQueryRequest;
import com.goldpac.jssb.pojo.vo.sical.PayQueryRequestBody;
import com.goldpac.jssb.pojo.vo.sical.PayRequest;
import com.goldpac.jssb.pojo.vo.sical.PayRequestBody;
import com.goldpac.jssb.pojo.vo.sical.PayRequestHead;
import com.goldpac.jssb.pojo.vo.sical.PayResponseBody;
import com.goldpac.jssb.pojo.vo.sical.SyncPayresultRq;
import com.goldpac.jssb.service.base.IParamService;
import com.goldpac.jssb.service.base.IPayService;
import com.goldpac.jssb.utils.ExceptionUtil;
import com.goldpac.jssb.utils.PayParams;
import com.goldpac.jssb.utils.Util;
import com.goldpac.vtm.core.exception.RestServiceException;
import com.goldpac.vtm.core.util.DateUtil;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author nan.jiang
 * @create 2023-11-20 14:21
 */
@Service
public class PayServiceImpl implements IPayService {

    private static Logger logger = LoggerFactory.getLogger(SocialServiceImpl.class);


    @Autowired
    private IParamService paramService;

    /**
     * 新版 应缴信息同步V2
     *
     * @param command
     * @return
     */
    @Override
    public BaseRp newSyncInfoV2(SyncInfoCommand command) {
        BaseRp rp = new BaseRp();
        try {
            logger.info("新版 应缴信息同步V2请求参数: {}", JSON.toJSONString(command));
            String url = "http://10.120.81.22:8080/httpservice/fszsjk";
            Param param = paramService.get("PKey", "key_payUrl");
            if (param == null) {
                paramService.saveOrUpdate("key_payUrl", url, "省厅正式支付URL");
            } else {
                url= param.getPValue();
            }
            BaseRequest bRequest = baseRequestHandler(command, url);
            logger.info("应缴信息同步V2请求密文报文->:"+JSON.toJSONString(bRequest));
            JSONObject res = requestServer(bRequest);//发送http请求
            logger.info(res.toJSONString());
            PayRequestBody pr = parsePayReq(res);
            //解密 缴款码
            String enPayCode = pr.getData();//eyJwYXlDb2RlIjoiNDEwMDAwMTkwMDAwMDEwMTM5OXgifQ
            //  String enPayCode = "eyJwYXlDb2RlIjoiNDEwMDAwMTkwMDAwMDEwMTM5OXgifQ";
            String payCodeJson = new String(Base64.decodeBase64(enPayCode), "UTF-8");//{"payCode":"4100001900000101399x"}
            JSONObject payCodeJsonObj = JSONObject.parseObject(payCodeJson);
            String paycode = (String) payCodeJsonObj.get("payCode");//4100001900000101399x
            PayParams.payCodeUrl.put(paycode, url);//记录url
            if(paycode == null || "".equals(paycode)){
                logger.info("获取缴款码为空！"+payCodeJsonObj.get("message"));
                throw new RuntimeException("获取缴款码为空！"+payCodeJsonObj.get("message"));
            }
            String image2base64 = responseResultV2(paycode);
            rp.setCode(0);//成功
            rp.setMessage(image2base64);//暂时存放base64二维码
            rp.setErrCode(paycode);//暂时存放缴款码
            //记录交易时间
        } catch (Exception e) {
            logger.info(ExceptionUtil.getTrace(e));
            rp.setCode(-1);
            rp.setMessage("新版 应缴信息同步V2系统异常:"+rp.getMessage());
            logger.info("新版 应缴信息同步V2系统异常: {}", rp.getMessage());
            return rp;
        }
        logger.info("新版 应缴信息同步V2响应前端: {}", JSON.toJSONString(command));
        return rp;
    }

    /**
     * 支付结果查询接口 2023.11.27 新增
     *
     * @param command
     * @return
     */
    @Override
    public BaseRp payQueryResult(SyncInfoCommand command) {
        logger.info("****************** start payQueryResult ******************");
        logger.info("--收到请求->支付结果查询：" + JSON.toJSONString(command));
        BaseRp rp = new BaseRp();
        rp.setCode(-1);
        String payCode = command.getBusyCode();//这里busycode用作存缴款码
        String transtime = PayParams.payCodeResultTranstime.get(payCode);//交易时间   Date        是   格式 YYYY-MM-DDHH:mm:ss
        //String  transtime = DateUtil.DateToString(DateUtil.nowTimestamp(), "yyyy-MM-dd HH:mm:ss");//YYYY-MM-DDHH:mm:ss
        if(transtime == null || "".equals(transtime)){
            rp.setCode(-1);
            rp.setMessage("支付结果查询接口(payQueryResult)->该缴款码["+payCode+"},没有查询到交易时间，请确认是否扫码缴费成功！");
            return rp;
        }
        String callbackQuery=command.getCallbackQuery();//是否回调查询   String      否   如果是，值传1
        SyncPayresultRq sprq = new SyncPayresultRq();
        try {
         // 报文头
            String transId = System.currentTimeMillis() + "";
            String tellerId = "0000";
            PayRequestHead head = new PayRequestHead();
            head.setTransId(transId);
            head.setOperatorName(tellerId);
//          head.setSender("JSFK");

            // 报文体
            PayQueryRequestBody body = new PayQueryRequestBody();
            String noise = System.currentTimeMillis() + "";

            sprq.setPayCode(payCode);
            sprq.setTranstime(transtime);
            sprq.setCallbackQuery(callbackQuery);

            String jsonParam = JSON.toJSONString(sprq);
            //logger.info("支付结果查询请求明文报文->jsonParam:"+jsonParam);
            String data = new String(Base64.encodeBase64URLSafe(jsonParam.getBytes("utf-8")));
            // String token = "RSTSBK@TOKEN";
            //String sign = signRequest(PayParams.fsToken, data, noise);//非税回调业务系统请求token
            String sign = signRequest(data, noise, PayParams.rsToken);//非税回调业务系统请求token
            body.setData(data);
            body.setNoise(noise);
            body.setSign(sign);
            body.setSrc("RSTSBK");//非税回调业务系统请求

            PayQueryRequest req = new PayQueryRequest();
            req.setHead(head);
            req.setBody(body);

            BaseRequest bRequest = new BaseRequest();
            bRequest.setHttpMethod(HttpMethodName.POST);
            bRequest.setConfig(new HttpClientConfiguration());
            HashMap<String,String> headers = new HashMap<String,String>();
            headers.put("Content-Type", "application/json; charset=utf-8");
            bRequest.setHeaders(headers);
            JSONObject obj = new JSONObject();
            obj.put("request", req);
            bRequest.addBody("body",obj.toJSONString());

            //支付结果查询接口 url
            String payResult = "http://10.120.81.22:8080/httpservice/dffszfjgcxqueryPayResult";
            Param param = paramService.get("PKey", "payResult");
            if (param == null) {
                paramService.saveOrUpdate("payResult", payResult, "支付结果查询URL");
            } else {
                payResult = param.getPValue();
            }
            bRequest.setUri(payResult);
            bRequest.setBodyFormat(EBodyFormat.RAW_JSON_ARRAY);
            //如果未收到来自缴费平台的通知结果,将持续发起查询
            try {
                int i=0;
                while(i<10) {
                    logger.info("支付结果查询请求加密报文->payQueryResult:"+JSON.toJSONString(bRequest));
                    JSONObject res = requestServer(bRequest);
                    //logger.info("支付结果查询返回加密报文->payQueryResult:"+JSON.toJSONString(res));
                    JSONObject js2 =  res.getJSONObject("response");//先解析response，再解析body，再转成对象
                    String js3 =  js2.getString("body");
                    JSONObject js4 =  JSONObject.parseObject(js3);
                    PayResponseBody prb = JSONObject.toJavaObject(js4, PayResponseBody.class);
                    String dataJsonStr = new String(Base64.decodeBase64(prb.getData()), "UTF-8");//{"payCode":"4100001900000101399x"}
                    logger.info("支付结果查询返回解密数据->dataJsonStr:"+dataJsonStr);
                    if("{}".equals(dataJsonStr)){
                        //返回{}代表没扫码缴费
                        Thread.sleep(1000L);
                        i++;
                        continue;
                    }
                    JSONObject dataJson = JSONObject.parseObject(dataJsonStr);
                    //0-待支付 1-待确    认 2-支付完成 3-支付失败 4 订单不存在 5 订单取消
                    String stats = (String) dataJson.get("stats");
                    if("SUCCESS".equals(prb.getResultCode())&&!"".equals(prb.getData())) {
                        //rp.setCode(0);
                        rp.setMessage(prb.getResultCode());
                        //查询之后清除map中该缴款码的值
                        PayParams.payCodeResult.remove(command.getBusyCode());
                        //PayParams.payCodeResultTranstime.remove(siRq.getBusyCode());
                        PayParams.payCodeUrl.remove(command.getBusyCode());
                        rp.setCode(Integer.parseInt(stats));
                        break;
                    }else{
                        rp.setCode(-1);
                        rp.setErrCode(prb.getResultCode());
                        rp.setMessage(dataJsonStr);
                    }
                    Thread.sleep(1000L);
                    i++;
                }
            } catch (InterruptedException e) {
                logger.info(ExceptionUtil.getTrace(e));
            }
        } catch (Exception e) {
            logger.info(ExceptionUtil.getTrace(e));
            rp.setCode(-1);
            rp.setMessage("支付结果查询接口(payQueryResult)->"+e.getMessage());
        }
        logger.info("支付结果查询接口响应前端: {}", JSON.toJSONString(rp));
        return rp;
    }
    
    @SuppressWarnings("unchecked")
    private BaseRequest baseRequestHandler(SyncInfoCommand command, String url) throws UnsupportedEncodingException {
        // 报文头
        String transId = System.currentTimeMillis() + "";
        String tellerId = "0000";
        PayRequestHead head = new PayRequestHead();
        head.setTransId(transId);
        head.setOperatorName(tellerId);
        //head.setSender("JSFK");

        // 报文体
        PayRequestBody body = new PayRequestBody();
        String noise = System.currentTimeMillis() + "";

        String busyCode = UUID.randomUUID().toString();
        command.setBusyCode(busyCode);
        command.setFillDate(DateUtil.DateToString(DateUtil.nowTimestamp(), "yyyy-MM-dd"));
        command.setEffDate(DateUtil.DateToString(DateUtil.nowTimestamp(), "yyyy-MM-dd"));
        command.setRegionCode("410000");
        command.setAgencyCode("504215");
        //获取缴款码的agencyname字段  由 河南省人力资源社会保障电子政务中心 变更为  河南省就业创业服务中心（河南省社会保障卡服务中心）
        //siRq.setAgencyName("河南省人力资源社会保障电子政务中心");
        command.setAgencyName("河南省就业创业服务中心（河南省社会保障卡服务中心）");
        command.setPayerAcct("");
        command.setPayerOpBkName("");
        command.setAmt(16);//缴款金额合计
        command.setOriAmt(16);//缴款书金额
        command.setDelayAmt(0);//滞纳金
        command.setRecAcct("");
        command.setSummary("");
        command.setNote1("");
        command.setNote2("");

        @SuppressWarnings("rawtypes")
        List<Map> listDetails = new ArrayList<Map>();
        @SuppressWarnings("rawtypes")
        Map detailsMap = new HashMap();
        detailsMap.put("itemIdCode", "");
        detailsMap.put("itemCode","141");
        detailsMap.put("itemName", "补办城镇职工社会保障卡(IC卡)工本费");
        detailsMap.put("standCode", "003");
        detailsMap.put("number", 1);//执收数量
        detailsMap.put("standard", 16);//执收标准
        detailsMap.put("amount", 16);//执收金额
        listDetails.add(detailsMap);
        command.setDetails(listDetails);

        String jsonParam = JSON.toJSONString(command);
        logger.info("应缴信息同步V2请求明文报文->jsonParam:"+jsonParam);
        String data = new String(Base64.encodeBase64URLSafe(jsonParam.getBytes("utf-8")));
        // String token = "RSTSBK@TOKEN";
        String sign = signRequest(data, noise,PayParams.rsToken);
        body.setData(data);
        body.setNoise(noise);
        body.setType("syncPayinfo");
        body.setSign(sign);
        body.setSrc("RSTSBK");

        PayRequest req = new PayRequest();
        req.setHead(head);
        req.setBody(body);

        BaseRequest bRequest = new BaseRequest();
        bRequest.setHttpMethod(HttpMethodName.POST);
        bRequest.setConfig(new HttpClientConfiguration());
        HashMap<String,String> headers = new HashMap<String,String>();
        headers.put("Content-Type", "application/json; charset=utf-8");
        bRequest.setHeaders(headers);
        JSONObject obj = new JSONObject();
        obj.put("request", req);

        bRequest.setUri(url);
        bRequest.addBody("body",obj.toJSONString());
        bRequest.setBodyFormat(EBodyFormat.RAW_JSON_ARRAY);
        return bRequest;
    }
    
    /**
    *
    * @Title: signRequest
    * @Description:获取sign值:
    * @param data
    * @param noise
    * @param token
    * @return
    * @return String
    */
   private static String signRequest(String data, String noise, String token) {
       String datas = token + data + noise;
       byte[] sign = DigestUtils.sha512(datas);
       byte[] signStr = Base64.encodeBase64URLSafe(sign);
       PayParams.map.put("rssign", new String(signStr));
       return new String(signStr);
   }
   
   /**
    * 发送Http请求
    *
    * @param request
    * @return
    */
   protected static JSONObject requestServer(BaseRequest request) {
       // 请求API
       BaseResponse response = CommonHttpClient.post(request);
       String resData = response.getBodyStr();
       Integer status = response.getStatus();
       if (status.equals(200) && !resData.equals("")) {
           try {
               JSONObject res =  JSONObject.parseObject(resData);
               return res;
           } catch (JSONException e) {
               return Util.getGeneralError(-1, resData);
           }
       } else {
           logger.info(String.format("call failed! response status: %d, data: %s", status, resData));
           return null;

       }
   }
   
   private PayRequestBody parsePayReq(JSONObject res) {
       JSONObject js2 =  res.getJSONObject("response");//先解析response，再解析body，再转成对象
       String js3 =  js2.getString("body");
       JSONObject js4 =  JSONObject.parseObject(js3);
       // 签名校验成功后,封装支付接口地址（包括参数）为二维码图片并发送给前端页面
       return JSONObject.toJavaObject(js4, PayRequestBody.class);
   }
   
   /**
   *
   * @Title: verifyResponse
   * @Description:签名校验
   * @param data
   * @param noise
   * @param token
   * @return boolean
   */
   public boolean verifyResponse(String data, String noise, String token, String resSign) {
       String datas = token + data + noise;
       byte[] sign = DigestUtils.sha512(datas);
       String signStr = new String(Base64.encodeBase64URLSafe(sign));
       if (!signStr.equals(resSign)) {
           // throw new RuntimeException("签名校验失败！");
           return false;
       }
       return true;
   }
   
   /**
    * 生成带支付宝背景的二维码
    * @Title: responseResult
    * @Description:检查签名验证是否成功,并封装为二维码供支付宝扫码
    * @param payCode
    * @return
    * @throws RestServiceException
    * @return boolean
    */
   protected String responseResultV2(String payCode) throws RestServiceException {
//     BaseRequest br = JSON.toJavaObject(res, BaseRequest.class);
       String image2base64 = null;
       // 获取body数据
       // {"body":{"data":{"payCode":"4100001900000100220j"},"src":"RSTSBK","noise":"1552133067215","sign":"wIuCdkw6g27vZbhQIAtJ2aMORCc2ns4jK7487x2A1b9tBNlZjxWCpeKeN4zN0dCkFy-czsIXUloZoaSic9TPIQ","type":"syncPayinfo"}}
       try {
           // 将JSONObject转换为对象
           SyncPayresultRq spresult = new SyncPayresultRq();
           if (payCode == null || "".equals(payCode)) {
               return "获取缴款码为空!";
           } else {
               spresult.setPayCode(payCode);
               spresult.setTranstime(DateUtil.DateToString(DateUtil.nowTimestamp(), "YYYY-MM-dd HH:mm:ss"));
               String notifyUrl = "http://172.24.5.54:5001/HnPublicServiceConsole/untax/syncPayResult8c67d81a.mvc";
               Param param = paramService.get("PKey", "notify_Url");
               if (param == null) {
                   paramService.saveOrUpdate("notify_Url", notifyUrl, "支付结果同步地址");
               } else {
                   notifyUrl = param.getPValue();
               }
               String deviceType = "2";
               param = paramService.get("PKey", "deviceType");
               if (param == null) {
                   paramService.saveOrUpdate("deviceType", deviceType, "终端类型");
               } else {
                   deviceType = param.getPValue();
               }
               String qrUrl = "http://fspay.hncz.gov.cn:9003/FSPayPlatform/payinfo/pay";
               param = paramService.get("PKey", "qrUrl");
               if (param == null) {
                   paramService.saveOrUpdate("qrUrl", deviceType, "支付正式地址");
               } else {
                   qrUrl = param.getPValue();
               }
               spresult.setNotify_URL(notifyUrl);
               spresult.setDeviceType(deviceType);
               String jsonParam = JSON.toJSONString(spresult);
               // 数据加密,并生成二维码
               String data = new String(Base64.encodeBase64URLSafe(jsonParam.getBytes("utf-8")));
               String noise = System.currentTimeMillis() + "";
               String sign = signRequest(data, noise, PayParams.rsToken);
               image2base64 = ZXingCode.getLogoQRCodeForAlipay(
                   qrUrl + "?src=RSTSBK&data=" + data + "&noise=" + noise + "&sign=" + sign,
                       null, " 支付宝扫描二维码 支付16元工本费");
           }
       } catch (UnsupportedEncodingException e) {
           e.printStackTrace();
       }
       return image2base64;
   }
}
